import com.alibaba.fastjson.JSON;
import com.iohao.game.action.skeleton.core.DataCodecKit;
import com.iohao.game.action.skeleton.core.codec.JsonDataCodec;
import com.iohao.game.action.skeleton.protocol.wrapper.StringValue;
import com.iohao.game.bolt.broker.client.external.bootstrap.ExternalKit;
import com.iohao.game.bolt.broker.client.external.bootstrap.message.ExternalMessage;
import com.iohao.game.bolt.broker.client.external.bootstrap.message.ExternalMessageCmdCode;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.java_websocket.client.WebSocketClient;
import org.java_websocket.drafts.Draft_6455;
import org.java_websocket.handshake.ServerHandshake;
import org.server.action.ActionCmd;
import org.server.domain.Login.LoginVerify;
import org.server.domain.Login.MyAttachment;
import org.server.domain.Result.Msg;
import org.server.domain.Room.Poker;
import org.server.domain.Room.RoomName;

import java.net.URI;
import java.net.URISyntaxException;
import java.nio.ByteBuffer;
import java.util.*;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;

@Slf4j
public class DemoWebsocketClientForHook {

    private WebSocketClient webSocketClient;

    public static JsonDataCodec jsonDataCodec = new JsonDataCodec();
    public static Idle idle = new Idle();

    private static String account;
    private static String password;

    private static final List<Integer> pokers = new ArrayList<>();

    public static void main(String[] args) throws URISyntaxException {
        DemoWebsocketClientForHook websocketClient = new DemoWebsocketClientForHook();
        Scanner sc = new Scanner(System.in);
        account = sc.next();
        password = sc.next();
        if (account == null) {
            return;
        }
        String next = "1234";
        websocketClient.init();
        while (!websocketClient.webSocketClient.isClosed()) {
            int op = sc.nextInt();
            try {
                switch (op) {
                    case 1:
                        System.out.println("输入要加入的房间名");
                        next = sc.next();
                        websocketClient.sendToServer(ExternalMessageCmdCode.biz, ActionCmd.ROOM, ActionCmd.ROOM_JOIN, new RoomName(next));
                        break;
                    case 2:
                        System.out.println("创建房间");
                        websocketClient.sendToServer(ExternalMessageCmdCode.biz, ActionCmd.ROOM, ActionCmd.ROOM_CREATE, null);
                        break;
                    case 3:
                        System.out.println("准备");
                        websocketClient.sendToServer(ExternalMessageCmdCode.biz, ActionCmd.ROOM, ActionCmd.ROOM_READY, new RoomName(next));
                        break;
                    case 4:
                        System.out.println("离开房间");
                        websocketClient.sendToServer(ExternalMessageCmdCode.biz, ActionCmd.ROOM, ActionCmd.ROOM_LEFT, new RoomName(next));
                        break;
                    case 5:
                        System.out.println("取消准备");
                        websocketClient.sendToServer(ExternalMessageCmdCode.biz, ActionCmd.ROOM, ActionCmd.ROOM_CANCEL_READY, new RoomName(next));
                        break;
                    case 6:
                        websocketClient.webSocketClient.close();
                        while (!websocketClient.webSocketClient.isClosed()) ;
                        break;
                    case 7:
                        System.out.println(pokers);
                        Random random = new Random(System.currentTimeMillis());
                        int num = random.nextInt(pokers.size());
                        System.out.println("出的牌数目为" + num);

                        List<Integer> realPokers = new ArrayList<>();
                        List<Integer> fakerPokers = new ArrayList<>();
                        for (int i = 0; i < num; i++) {
                            Integer aim = pokers.get(random.nextInt(pokers.size()));
                            realPokers.add(aim);
                            pokers.remove(aim);
                        }
                        System.out.println("选的牌为");
                        System.out.println(realPokers);
                        System.out.println("假牌面为");
                        Integer aim = pokers.get(random.nextInt(pokers.size()));
                        System.out.println(num);
                        for (int i = 0; i < num; i++) {
                            fakerPokers.add(aim);
                        }
                        System.out.println(fakerPokers);
                        Poker poker = new Poker();
                        poker.setRoomName(next);
                        poker.setRealPokers(JSON.toJSONString(realPokers));
                        poker.setFakePoker(JSON.toJSONString(fakerPokers));
                        poker.setIsTrue(new HashSet<>(realPokers).containsAll(fakerPokers) ? 1 : 0);
                        websocketClient.sendToServer(ExternalMessageCmdCode.biz, ActionCmd.ROOM, ActionCmd.ROOM_PLAY, poker);
                        break;
                    case 8:
                        System.out.println("发牌");
                        String roomName = sc.next();
                        StringValue stringValue = new StringValue();
                        stringValue.value = roomName;
                        websocketClient.sendToServer(ExternalMessageCmdCode.biz, ActionCmd.ADMIN, ActionCmd.ADMIN_DEAL, stringValue);
                        break;
                    case 9:
                        System.out.println("过牌");
                        websocketClient.sendToServer(ExternalMessageCmdCode.biz, ActionCmd.ROOM, ActionCmd.ROOM_PASS, new Poker(next, null, null, null));
                        break;
                    case 10:
                        System.out.println("进行质疑");
                        websocketClient.sendToServer(ExternalMessageCmdCode.biz, ActionCmd.ROOM, ActionCmd.ROOM_QUESTION, new Poker(next, null, null, null));
                        break;
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

    public static byte[] createExternalMessage(int cmd, int subCmd, Object data) {

        // 游戏框架内置的协议， 与游戏前端相互通讯的协议
        ExternalMessage externalMessage = ExternalKit
                // 路由、子路由、业务数据
                .createExternalMessage(cmd, subCmd, data);

        // 转为字节
        return DataCodecKit.encode(externalMessage);
    }

    private void init() throws URISyntaxException {
        // 这里模拟游戏客户端
        // 连接游戏服务器的地址
        String wsUrl = "ws://192.168.3.14:10101/websocket";

        webSocketClient = new WebSocketClient(new URI(wsUrl), new Draft_6455()) {
            @SneakyThrows
            @Override
            public void onOpen(ServerHandshake serverHandshake) {
                LoginVerify loginVerify = new LoginVerify();
                loginVerify.account = account;
                loginVerify.password = password;
//                loginVerify.Jwt = jwt;
                sendToServer(ExternalMessageCmdCode.biz, ActionCmd.LOG, ActionCmd.LOG_LOGIN, loginVerify);
                if (!idle.isStart()) {
                    idle.start(this);
                }
            }

            @Override
            public void onMessage(ByteBuffer byteBuffer) {
                // 接收服务器返回的消息
                byte[] dataContent = byteBuffer.array();
                ExternalMessage s = DataCodecKit.decode(dataContent, ExternalMessage.class);
                if (s.getCmdCode() != ExternalMessageCmdCode.idle) {
                    Msg decode = DataCodecKit.decode(s.getData(), Msg.class);
                    if (s.getCmdMerge() == 262144) {
                        MyAttachment myAttachment = JSON.parseObject(decode.data, MyAttachment.class);
                        log.info("收到消息 ExternalMessage ========== \n{}", myAttachment);
                        return;
                    }
                    log.info("收到消息 ExternalMessage ========== \n{}", decode);
                    if (s.getCmdMerge() == 65536) {
                        List<Integer> integers = JSON.parseArray(decode.data, Integer.class);
                        System.out.println(integers);
                        pokers.addAll(integers);
                    }
                }
            }

            @Override
            public void onMessage(String s) {

            }

            @Override
            public void onClose(int i, String s, boolean b) {
                idle.end();
            }

            @Override
            public void onError(Exception e) {

            }
        };

        // 开始连接服务器
        webSocketClient.connect();
    }

    public void sendToServer(int cmdCode, int cmd, int subCmd, Object data) {
        // 路由, 对应服务端逻辑服的业务类路由地址 （登录）
        // 创建对外服协议，用于请求游戏服
        byte[] externalMessageBytes = createExternalMessage(cmd, subCmd, data);
        // 发送数据到游戏服务器
        this.webSocketClient.send(externalMessageBytes);
    }
}

class Idle {
    private boolean isOpen;
    private final ScheduledExecutorService service;

    public Idle() {
        this.isOpen = false;
        this.service = Executors.newScheduledThreadPool(1);
        ;
    }

    public boolean isStart() {
        return this.isOpen;
    }

    public void start(WebSocketClient webSocketClient) {
        this.isOpen = true;
        int cmd = ActionCmd.LOG;
        int subCmd = ActionCmd.LOG_IDLE;

        ExternalMessage externalMessage = new ExternalMessage();
        externalMessage.setData(null);
        externalMessage.setCmdMerge(ActionCmd.LOG, ActionCmd.LOG_IDLE);
        externalMessage.setCmdCode(ExternalMessageCmdCode.idle);

        // 创建对外服协议，用于请求游戏服
        byte[] externalMessageBytes = DataCodecKit.encode(externalMessage);
        service.scheduleAtFixedRate(() -> webSocketClient.send(externalMessageBytes), 2, 2, TimeUnit.SECONDS);
    }

    public void end() {
        this.isOpen = false;
        service.shutdown();
    }
}